<template>
    <view class="uni-data-checklist" :style="{ 'margin-top': isTop + 'px' }">
        <template v-if="!isLocal">
            <view class="uni-data-loading">
                <uni-load-more
                    v-if="!mixinDatacomErrorMessage"
                    status="loading"
                    icon-type="snow"
                    :icon-size="18"
                    :content-text="contentText"
                ></uni-load-more>
                <text v-else>{{ mixinDatacomErrorMessage }}</text>
            </view>
        </template>
        <template v-else>
            <checkbox-group
                v-if="multiple"
                class="checklist-group"
                :class="{ 'is-list': mode === 'list' || wrap }"
                @change="change"
            >
                <label
                    v-for="(item, index) in dataList"
                    :key="index"
                    class="checklist-box"
                    :class="[
                        'is--' + mode,
                        item.selected ? 'is-checked' : '',
                        disabled || !!item.disabled ? 'is-disable' : '',
                        index !== 0 && mode === 'list' ? 'is-list-border' : ''
                    ]"
                    :style="item.styleBackgroud"
                >
                    <checkbox
                        class="hidden"
                        hidden
                        :disabled="disabled || !!item.disabled"
                        :value="item[map.value] + ''"
                        :checked="item.selected"
                    />
                    <view
                        v-if="(mode !== 'tag' && mode !== 'list') || (mode === 'list' && icon === 'left')"
                        class="checkbox__inner"
                        :style="item.styleIcon"
                    >
                        <view class="checkbox__inner-icon"></view>
                    </view>
                    <view class="checklist-content" :class="{ 'list-content': mode === 'list' && icon === 'left' }">
                        <text class="checklist-text" :style="item.styleIconText">{{ item[map.text] }}</text>
                        <view
                            v-if="mode === 'list' && icon === 'right'"
                            class="checkobx__list"
                            :style="item.styleBackgroud"
                        ></view>
                    </view>
                </label>
            </checkbox-group>
            <radio-group
                v-else
                class="checklist-group"
                :class="{ 'is-list': mode === 'list', 'is-wrap': wrap }"
                @change="change"
            >
                <label
                    v-for="(item, index) in dataList"
                    :key="index"
                    class="checklist-box"
                    :class="[
                        'is--' + mode,
                        item.selected ? 'is-checked' : '',
                        disabled || !!item.disabled ? 'is-disable' : '',
                        index !== 0 && mode === 'list' ? 'is-list-border' : ''
                    ]"
                    :style="item.styleBackgroud"
                >
                    <radio
                        class="hidden"
                        hidden
                        :disabled="disabled || item.disabled"
                        :value="item[map.value] + ''"
                        :checked="item.selected"
                    />
                    <view
                        v-if="(mode !== 'tag' && mode !== 'list') || (mode === 'list' && icon === 'left')"
                        class="radio__inner"
                        :style="item.styleBackgroud"
                    >
                        <view class="radio__inner-icon" :style="item.styleIcon"></view>
                    </view>
                    <view class="checklist-content" :class="{ 'list-content': mode === 'list' && icon === 'left' }">
                        <text class="checklist-text" :style="item.styleIconText">{{ item[map.text] }}</text>
                        <view
                            v-if="mode === 'list' && icon === 'right'"
                            :style="item.styleRightIcon"
                            class="checkobx__list"
                        ></view>
                    </view>
                </label>
            </radio-group>
        </template>
    </view>
</template>

<script>
/**
 * DataChecklist 数据选择器
 * @description 通过数据渲染 checkbox 和 radio
 * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
 * @property {String} mode = [default| list | button | tag] 显示模式
 * @value default  	默认横排模式
 * @value list		列表模式
 * @value button	按钮模式
 * @value tag 		标签模式
 * @property {Boolean} multiple = [true|false] 是否多选
 * @property {Array|String|Number} value 默认值
 * @property {Array} localdata 本地数据 ，格式 [{text:'',value:''}]
 * @property {Number|String} min 最小选择个数 ，multiple为true时生效
 * @property {Number|String} max 最大选择个数 ，multiple为true时生效
 * @property {Boolean} wrap 是否换行显示
 * @property {String} icon = [left|right]  list 列表模式下icon显示位置
 * @property {Boolean} selectedColor 选中颜色
 * @property {Boolean} emptyText 没有数据时显示的文字 ，本地数据无效
 * @property {Boolean} selectedTextColor 选中文本颜色，如不填写则自动显示
 * @property {Object} map 字段映射， 默认 map={text:'text',value:'value'}
 * @value left 左侧显示
 * @value right 右侧显示
 * @event {Function} change  选中发生变化触发
 */

export default {
    name: "UniDataChecklist",
    mixins: [uniCloud.mixinDatacom || {}],
    props: {
        mode: {
            type: String,
            default: "default"
        },

        multiple: {
            type: Boolean,
            default: false
        },
        value: {
            type: [Array, String, Number],
            default() {
                return "";
            }
        },
        // TODO vue3
        modelValue: {
            type: [Array, String, Number],
            default() {
                return "";
            }
        },
        localdata: {
            type: Array,
            default() {
                return [];
            }
        },
        min: {
            type: [Number, String],
            default: ""
        },
        max: {
            type: [Number, String],
            default: ""
        },
        wrap: {
            type: Boolean,
            default: false
        },
        icon: {
            type: String,
            default: "left"
        },
        selectedColor: {
            type: String,
            default: ""
        },
        selectedTextColor: {
            type: String,
            default: ""
        },
        emptyText: {
            type: String,
            default: "暂无数据"
        },
        disabled: {
            type: Boolean,
            default: false
        },
        map: {
            type: Object,
            default() {
                return {
                    text: "text",
                    value: "value"
                };
            }
        }
    },
    emits: ["input", "update:modelValue", "change"],
    data() {
        return {
            dataList: [],
            range: [],
            contentText: {
                contentdown: "查看更多",
                contentrefresh: "加载中",
                contentnomore: "没有更多"
            },
            isLocal: true,
            styles: {
                selectedColor: "#2979ff",
                selectedTextColor: "#666"
            },
            isTop: 0
        };
    },
    computed: {
        dataValue() {
            if (this.value === "") return this.modelValue;
            if (this.modelValue === "") return this.value;
            return this.value;
        }
    },
    watch: {
        localdata: {
            handler(newVal) {
                this.range = newVal;
                this.dataList = this.getDataList(this.getSelectedValue(newVal));
            },
            deep: true
        },
        mixinDatacomResData(newVal) {
            this.range = newVal;
            this.dataList = this.getDataList(this.getSelectedValue(newVal));
        },
        value(newVal) {
            this.dataList = this.getDataList(newVal);
            // fix by mehaotian is_reset 在 uni-forms 中定义
            // if(!this.is_reset){
            // 	this.is_reset = false
            // 	this.formItem && this.formItem.setValue(newVal)
            // }
        },
        modelValue(newVal) {
            this.dataList = this.getDataList(newVal);
            // if(!this.is_reset){
            // 	this.is_reset = false
            // 	this.formItem && this.formItem.setValue(newVal)
            // }
        }
    },
    created() {
        // this.form = this.getForm('uniForms')
        // this.formItem = this.getForm('uniFormsItem')
        // this.formItem && this.formItem.setValue(this.value)

        // if (this.formItem) {
        // 	this.isTop = 6
        // 	if (this.formItem.name) {
        // 		// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
        // 		if(!this.is_reset){
        // 			this.is_reset = false
        // 			this.formItem.setValue(this.dataValue)
        // 		}
        // 		this.rename = this.formItem.name
        // 		this.form.inputChildrens.push(this)
        // 	}
        // }

        if (this.localdata && this.localdata.length !== 0) {
            this.isLocal = true;
            this.range = this.localdata;
            this.dataList = this.getDataList(this.getSelectedValue(this.range));
        } else {
            if (this.collection) {
                this.isLocal = false;
                this.loadData();
            }
        }
    },
    methods: {
        loadData() {
            this.mixinDatacomGet()
                .then((res) => {
                    this.mixinDatacomResData = res.result.data;
                    if (this.mixinDatacomResData.length === 0) {
                        this.isLocal = false;
                        this.mixinDatacomErrorMessage = this.emptyText;
                    } else {
                        this.isLocal = true;
                    }
                })
                .catch((err) => {
                    this.mixinDatacomErrorMessage = err.message;
                });
        },
        /**
         * 获取父元素实例
         */
        getForm(name = "uniForms") {
            let parent = this.$parent;
            let parentName = parent.$options.name;
            while (parentName !== name) {
                parent = parent.$parent;
                if (!parent) return false;
                parentName = parent.$options.name;
            }
            return parent;
        },
        change(e) {
            const values = e.detail.value;

            let detail = {
                value: [],
                data: []
            };

            if (this.multiple) {
                this.range.forEach((item) => {
                    if (values.includes(item[this.map.value] + "")) {
                        detail.value.push(item[this.map.value]);
                        detail.data.push(item);
                    }
                });
            } else {
                const range = this.range.find((item) => item[this.map.value] + "" === values);
                if (range) {
                    detail = {
                        value: range[this.map.value],
                        data: range
                    };
                }
            }
            // this.formItem && this.formItem.setValue(detail.value)
            // TODO 兼容 vue2
            this.$emit("input", detail.value);
            // // TOTO 兼容 vue3
            this.$emit("update:modelValue", detail.value);
            this.$emit("change", {
                detail
            });
            if (this.multiple) {
                // 如果 v-model 没有绑定 ，则走内部逻辑
                // if (this.value.length === 0) {
                this.dataList = this.getDataList(detail.value, true);
                // }
            } else {
                this.dataList = this.getDataList(detail.value);
            }
        },

        /**
         * 获取渲染的新数组
         * @param {Object} value 选中内容
         */
        getDataList(value) {
            // 解除引用关系，破坏原引用关系，避免污染源数据
            let dataList = JSON.parse(JSON.stringify(this.range));
            let list = [];
            if (this.multiple) {
                if (!Array.isArray(value)) {
                    value = [];
                }
            }
            dataList.forEach((item, index) => {
                item.disabled = item.disable || item.disabled || false;
                if (this.multiple) {
                    if (value.length > 0) {
                        let have = value.find((val) => val === item[this.map.value]);
                        item.selected = have !== undefined;
                    } else {
                        item.selected = false;
                    }
                } else {
                    item.selected = value === item[this.map.value];
                }

                list.push(item);
            });
            return this.setRange(list);
        },
        /**
         * 处理最大最小值
         * @param {Object} list
         */
        setRange(list) {
            let selectList = list.filter((item) => item.selected);
            let min = Number(this.min) || 0;
            let max = Number(this.max) || "";
            list.forEach((item, index) => {
                if (this.multiple) {
                    if (selectList.length <= min) {
                        let have = selectList.find((val) => val[this.map.value] === item[this.map.value]);
                        if (have !== undefined) {
                            item.disabled = true;
                        }
                    }

                    if (selectList.length >= max && max !== "") {
                        let have = selectList.find((val) => val[this.map.value] === item[this.map.value]);
                        if (have === undefined) {
                            item.disabled = true;
                        }
                    }
                }
                this.setStyles(item, index);
                list[index] = item;
            });
            return list;
        },
        /**
         * 设置 class
         * @param {Object} item
         * @param {Object} index
         */
        setStyles(item, index) {
            //  设置自定义样式
            item.styleBackgroud = this.setStyleBackgroud(item);
            item.styleIcon = this.setStyleIcon(item);
            item.styleIconText = this.setStyleIconText(item);
            item.styleRightIcon = this.setStyleRightIcon(item);
        },

        /**
         * 获取选中值
         * @param {Object} range
         */
        getSelectedValue(range) {
            if (!this.multiple) return this.dataValue;
            let selectedArr = [];
            range.forEach((item) => {
                if (item.selected) {
                    selectedArr.push(item[this.map.value]);
                }
            });
            return this.dataValue.length > 0 ? this.dataValue : selectedArr;
        },

        /**
         * 设置背景样式
         */
        setStyleBackgroud(item) {
            let styles = {};
            let selectedColor = this.selectedColor ? this.selectedColor : "#2979ff";
            if (this.selectedColor) {
                if (this.mode !== "list") {
                    styles["border-color"] = item.selected ? selectedColor : "#DCDFE6";
                }
                if (this.mode === "tag") {
                    styles["background-color"] = item.selected ? selectedColor : "#f5f5f5";
                }
            }
            let classles = "";
            for (let i in styles) {
                classles += `${i}:${styles[i]};`;
            }
            return classles;
        },
        setStyleIcon(item) {
            let styles = {};
            let classles = "";
            if (this.selectedColor) {
                let selectedColor = this.selectedColor ? this.selectedColor : "#2979ff";
                styles["background-color"] = item.selected ? selectedColor : "#fff";
                styles["border-color"] = item.selected ? selectedColor : "#DCDFE6";

                if (!item.selected && item.disabled) {
                    styles["background-color"] = "#F2F6FC";
                    styles["border-color"] = item.selected ? selectedColor : "#DCDFE6";
                }
            }
            for (let i in styles) {
                classles += `${i}:${styles[i]};`;
            }
            return classles;
        },
        setStyleIconText(item) {
            let styles = {};
            let classles = "";
            if (this.selectedColor) {
                let selectedColor = this.selectedColor ? this.selectedColor : "#2979ff";
                if (this.mode === "tag") {
                    styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : "#fff") : "#666";
                } else {
                    styles.color = item.selected
                        ? this.selectedTextColor
                            ? this.selectedTextColor
                            : selectedColor
                        : "#666";
                }
                if (!item.selected && item.disabled) {
                    styles.color = "#999";
                }
            }
            for (let i in styles) {
                classles += `${i}:${styles[i]};`;
            }
            return classles;
        },
        setStyleRightIcon(item) {
            let styles = {};
            let classles = "";
            if (this.mode === "list") {
                styles["border-color"] = item.selected ? this.styles.selectedColor : "#DCDFE6";
            }
            for (let i in styles) {
                classles += `${i}:${styles[i]};`;
            }

            return classles;
        }
    }
};
</script>

<style lang="scss">
$uni-primary: #2979ff !default;
$border-color: #dcdfe6;
$disable: 0.4;

@mixin flex {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
}

.uni-data-loading {
    @include flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    height: 36px;
    padding-left: 10px;
    color: #999;
}

.uni-data-checklist {
    position: relative;
    z-index: 0;
    flex: 1;

    // 多选样式
    .checklist-group {
        @include flex;
        flex-direction: row;
        flex-wrap: wrap;

        &.is-list {
            flex-direction: column;
        }

        .checklist-box {
            @include flex;
            flex-direction: row;
            align-items: center;
            position: relative;
            margin: 5px 0;
            margin-right: 25px;

            .hidden {
                position: absolute;
                opacity: 0;
            }

            // 文字样式
            .checklist-content {
                @include flex;
                flex: 1;
                flex-direction: row;
                align-items: center;
                justify-content: space-between;

                .checklist-text {
                    font-size: 14px;
                    color: #666;
                    margin-left: 5px;
                    line-height: 14px;
                }

                .checkobx__list {
                    border-right-width: 1px;
                    border-right-color: #007aff;
                    border-right-style: solid;
                    border-bottom-width: 1px;
                    border-bottom-color: #007aff;
                    border-bottom-style: solid;
                    height: 12px;
                    width: 6px;
                    left: -5px;
                    transform-origin: center;
                    transform: rotate(45deg);
                    opacity: 0;
                }
            }

            // 多选样式
            .checkbox__inner {
                /* #ifndef APP-NVUE */
                flex-shrink: 0;
                box-sizing: border-box;
                /* #endif */
                position: relative;
                width: 16px;
                height: 16px;
                border: 1px solid $border-color;
                border-radius: 4px;
                background-color: #fff;
                z-index: 1;

                .checkbox__inner-icon {
                    position: absolute;
                    /* #ifdef APP-NVUE */
                    top: 2px;
                    /* #endif */
                    /* #ifndef APP-NVUE */
                    top: 1px;
                    /* #endif */
                    left: 5px;
                    height: 8px;
                    width: 4px;
                    border-right-width: 1px;
                    border-right-color: #fff;
                    border-right-style: solid;
                    border-bottom-width: 1px;
                    border-bottom-color: #fff;
                    border-bottom-style: solid;
                    opacity: 0;
                    transform-origin: center;
                    transform: rotate(40deg);
                }
            }

            // 单选样式
            .radio__inner {
                @include flex;
                /* #ifndef APP-NVUE */
                flex-shrink: 0;
                box-sizing: border-box;
                /* #endif */
                justify-content: center;
                align-items: center;
                position: relative;
                width: 16px;
                height: 16px;
                border: 1px solid $border-color;
                border-radius: 16px;
                background-color: #fff;
                z-index: 1;

                .radio__inner-icon {
                    width: 8px;
                    height: 8px;
                    border-radius: 10px;
                    opacity: 0;
                }
            }

            // 默认样式
            &.is--default {
                // 禁用
                &.is-disable {
                    /* #ifdef H5 */
                    cursor: not-allowed;

                    /* #endif */
                    .checkbox__inner {
                        background-color: #f2f6fc;
                        border-color: $border-color;
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                    }

                    .radio__inner {
                        background-color: #f2f6fc;
                        border-color: $border-color;
                    }

                    .checklist-text {
                        color: #999;
                    }
                }

                // 选中
                &.is-checked {
                    .checkbox__inner {
                        border-color: $uni-primary;
                        background-color: $uni-primary;

                        .checkbox__inner-icon {
                            opacity: 1;
                            transform: rotate(45deg);
                        }
                    }

                    .radio__inner {
                        border-color: $uni-primary;

                        .radio__inner-icon {
                            opacity: 1;
                            background-color: $uni-primary;
                        }
                    }

                    .checklist-text {
                        color: $uni-primary;
                    }

                    // 选中禁用
                    &.is-disable {
                        .checkbox__inner {
                            opacity: $disable;
                        }

                        .checklist-text {
                            opacity: $disable;
                        }

                        .radio__inner {
                            opacity: $disable;
                        }
                    }
                }
            }

            // 按钮样式
            &.is--button {
                margin-right: 10px;
                padding: 5px 10px;
                border: 1px $border-color solid;
                border-radius: 3px;
                transition: border-color 0.2s;

                // 禁用
                &.is-disable {
                    /* #ifdef H5 */
                    cursor: not-allowed;
                    /* #endif */
                    border: 1px #eee solid;
                    opacity: $disable;

                    .checkbox__inner {
                        background-color: #f2f6fc;
                        border-color: $border-color;
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                    }

                    .radio__inner {
                        background-color: #f2f6fc;
                        border-color: $border-color;
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                    }

                    .checklist-text {
                        color: #999;
                    }
                }

                &.is-checked {
                    border-color: $uni-primary;

                    .checkbox__inner {
                        border-color: $uni-primary;
                        background-color: $uni-primary;

                        .checkbox__inner-icon {
                            opacity: 1;
                            transform: rotate(45deg);
                        }
                    }

                    .radio__inner {
                        border-color: $uni-primary;

                        .radio__inner-icon {
                            opacity: 1;
                            background-color: $uni-primary;
                        }
                    }

                    .checklist-text {
                        color: $uni-primary;
                    }

                    // 选中禁用
                    &.is-disable {
                        opacity: $disable;
                    }
                }
            }

            // 标签样式
            &.is--tag {
                margin-right: 10px;
                padding: 5px 10px;
                border: 1px $border-color solid;
                border-radius: 3px;
                background-color: #f5f5f5;

                .checklist-text {
                    margin: 0;
                    color: #666;
                }

                // 禁用
                &.is-disable {
                    /* #ifdef H5 */
                    cursor: not-allowed;
                    /* #endif */
                    opacity: $disable;
                }

                &.is-checked {
                    background-color: $uni-primary;
                    border-color: $uni-primary;

                    .checklist-text {
                        color: #fff;
                    }
                }
            }

            // 列表样式
            &.is--list {
                /* #ifndef APP-NVUE */
                display: flex;
                /* #endif */
                padding: 10px 15px;
                padding-left: 0;
                margin: 0;

                &.is-list-border {
                    border-top: 1px #eee solid;
                }

                // 禁用
                &.is-disable {
                    /* #ifdef H5 */
                    cursor: not-allowed;

                    /* #endif */
                    .checkbox__inner {
                        background-color: #f2f6fc;
                        border-color: $border-color;
                        /* #ifdef H5 */
                        cursor: not-allowed;
                        /* #endif */
                    }

                    .checklist-text {
                        color: #999;
                    }
                }

                &.is-checked {
                    .checkbox__inner {
                        border-color: $uni-primary;
                        background-color: $uni-primary;

                        .checkbox__inner-icon {
                            opacity: 1;
                            transform: rotate(45deg);
                        }
                    }

                    .radio__inner {
                        border-color: $uni-primary;
                        .radio__inner-icon {
                            opacity: 1;
                            background-color: $uni-primary;
                        }
                    }

                    .checklist-text {
                        color: $uni-primary;
                    }

                    .checklist-content {
                        .checkobx__list {
                            opacity: 1;
                            border-color: $uni-primary;
                        }
                    }

                    // 选中禁用
                    &.is-disable {
                        .checkbox__inner {
                            opacity: $disable;
                        }

                        .checklist-text {
                            opacity: $disable;
                        }
                    }
                }
            }
        }
    }
}
</style>
